package org.grid.model;

import java.io.*;
import java.rmi.*;
import org.grid.model.rmi.*;

/**
 * Classe representante de um nó no Grid
 * É capaz de armazenar um objeto RMI do nó para ser utilizado pela máquina cliente, além de possibilitar
 * a persistência de seus dados
 * @author wellington
 */
public class Node implements Serializable, Comparable<Node> {

    /**
     * Nome padrão para um nó
     */
    public static final String DEFAULT_NAME = "logCalculator";

    /// <editor-fold defaultstate="collapsed" desc="Attributos">
    private static final long serialVersionUID = 13L;
    private String address;
    private Integer port;
    private String description;
    private transient LogCalculator logCalculator;
    /// </editor-fold>

    /// <editor-fold defaultstate="collapsed" desc="Construtores">
    /**
     * Construtor vazio para a persistencia
     */
    public Node() {
    }

    /**
     *  Construtor para inicializar um nó
     * @param address é o endereço do nó na rede
     * @param port é a porta que o servidor RMI está escutando
     * @param description um nome para identificação do nó. i.e. o nome do computador
     */
    public Node(String address, Integer port, String description) {
        this.address = address;
        this.port = port;
        this.description = description;
    }

    /**
     *  Construtor para inicializar um nó
     * @param address é o endereço do nó na rede
     * @param port é a porta que o servidor RMI está escutando
     * @param description um nome para identificação do nó. i.e. o nome do computador
     * @param logCalculator o objeto LogCalculator para realização dos cálculos
     */
    public Node(String address, Integer port, String description, LogCalculator logCalculator) {
        this.address = address;
        this.port = port;
        this.description = description;
        this.logCalculator = logCalculator;
    }
    /// </editor-fold>
    
    /// <editor-fold defaultstate="collapsed" desc="Métodos sobreescritos">
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Node other = (Node) obj;
        if (this.address != other.address && (this.address == null || !this.address.equals(other.address))) {
            return false;
        }
        if (this.port != other.port && (this.port == null || !this.port.equals(other.port))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (this.address != null ? this.address.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return String.format("rmi://%s:%d/%s", address, port, DEFAULT_NAME);
    }

    public int compareTo(Node o) {
        int i = description.compareTo(o.getDescription());
        if (i == 0) {
            i = address.compareTo(o.getAddress());
            if (i == 0) {
                i = port.compareTo(o.getPort());
            }
        }
        return i;
    }
    /// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="getters and setters">
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) throws ValueRequiredException {
        if (address.length() < 7) {
            throw new ValueRequiredException("O endereço informado é inválido");
        }
        this.address = address;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) throws ValueRequiredException {
        if (port <= 0) {
            throw new ValueRequiredException("Número de porta inválido");
        }
        this.port = port;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) throws ValueRequiredException {
        if (description.length() == 0) {
            throw new ValueRequiredException("A descrição deve ser preenchida");
        }
        this.description = description;
    }

    /**
     * Obtém o objeto do grid para processamento.
     * @param forceRefresh obriga a retormar o objeto do servidor mesmo que a referência do mesmo não esteja vazia
     * @return um objeto instanciado do Servidor RMI
     */
    public LogCalculator getLogCalculator(boolean forceRefresh) {
        try {
            if (logCalculator == null || forceRefresh) {
                logCalculator = (LogCalculator) Naming.lookup(toString());
            }
        } catch (Exception ex) {
            logCalculator = null;
        }
        return logCalculator;
    }

    public LogCalculator getLogCalculator() {
        return logCalculator;
    }

    public void setLogCalculator(LogCalculator logCalculator) {
        this.logCalculator = logCalculator;
    }

    // </editor-fold>
}